1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package javax.swing.text.html;
26
27 import sun.swing.SwingUtilities2;
28 import java.util.*;
29 import java.awt.*;
30 import java.io.*;
31 import java.net.*;
32 import javax.swing.Icon;
33 import javax.swing.ImageIcon;
34 import javax.swing.UIManager;
35 import javax.swing.border.*;
36 import javax.swing.event.ChangeListener;
37 import javax.swing.text.*;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 public class StyleSheet extends StyleContext {
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 public StyleSheet() {
166 super();
167 selectorMapping = new SelectorMapping(0);
168 resolvedStyles = new Hashtable<String, ResolvedStyle>();
169 if (css == null) {
170 css = new CSS();
171 }
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 public Style getRule(HTML.Tag t, Element e) {
190 SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
191
192 try {
193
194 Vector<Element> searchContext = sb.getVector();
195
196 for (Element p = e; p != null; p = p.getParentElement()) {
197 searchContext.addElement(p);
198 }
199
200
201 int n = searchContext.size();
202 StringBuffer cacheLookup = sb.getStringBuffer();
203 AttributeSet attr;
204 String eName;
205 Object name;
206
207
208 for (int counter = n - 1; counter >= 1; counter--) {
209 e = searchContext.elementAt(counter);
210 attr = e.getAttributes();
211 name = attr.getAttribute(StyleConstants.NameAttribute);
212 eName = name.toString();
213 cacheLookup.append(eName);
214 if (attr != null) {
215 if (attr.isDefined(HTML.Attribute.ID)) {
216 cacheLookup.append('#');
217 cacheLookup.append(attr.getAttribute
218 (HTML.Attribute.ID));
219 }
220 else if (attr.isDefined(HTML.Attribute.CLASS)) {
221 cacheLookup.append('.');
222 cacheLookup.append(attr.getAttribute
223 (HTML.Attribute.CLASS));
224 }
225 }
226 cacheLookup.append(' ');
227 }
228 cacheLookup.append(t.toString());
229 e = searchContext.elementAt(0);
230 attr = e.getAttributes();
231 if (e.isLeaf()) {
232
233 Object testAttr = attr.getAttribute(t);
234 if (testAttr instanceof AttributeSet) {
235 attr = (AttributeSet)testAttr;
236 }
237 else {
238 attr = null;
239 }
240 }
241 if (attr != null) {
242 if (attr.isDefined(HTML.Attribute.ID)) {
243 cacheLookup.append('#');
244 cacheLookup.append(attr.getAttribute(HTML.Attribute.ID));
245 }
246 else if (attr.isDefined(HTML.Attribute.CLASS)) {
247 cacheLookup.append('.');
248 cacheLookup.append(attr.getAttribute
249 (HTML.Attribute.CLASS));
250 }
251 }
252
253 Style style = getResolvedStyle(cacheLookup.toString(),
254 searchContext, t);
255 return style;
256 }
257 finally {
258 SearchBuffer.releaseSearchBuffer(sb);
259 }
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273 public Style getRule(String selector) {
274 selector = cleanSelectorString(selector);
275 if (selector != null) {
276 Style style = getResolvedStyle(selector);
277 return style;
278 }
279 return null;
280 }
281
282
283
284
285
286
287 public void addRule(String rule) {
288 if (rule != null) {
289
290
291 final String baseUnitsDisable = "BASE_SIZE_DISABLE";
292 final String baseUnits = "BASE_SIZE ";
293 final String w3cLengthUnitsEnable = "W3C_LENGTH_UNITS_ENABLE";
294 final String w3cLengthUnitsDisable = "W3C_LENGTH_UNITS_DISABLE";
295 if (rule == baseUnitsDisable) {
296 sizeMap = sizeMapDefault;
297 } else if (rule.startsWith(baseUnits)) {
298 rebaseSizeMap(Integer.
299 parseInt(rule.substring(baseUnits.length())));
300 } else if (rule == w3cLengthUnitsEnable) {
301 w3cLengthUnits = true;
302 } else if (rule == w3cLengthUnitsDisable) {
303 w3cLengthUnits = false;
304 } else {
305 CssParser parser = new CssParser();
306 try {
307 parser.parse(getBase(), new StringReader(rule), false, false);
308 } catch (IOException ioe) { }
309 }
310 }
311 }
312
313
314
315
316
317
318 public AttributeSet getDeclaration(String decl) {
319 if (decl == null) {
320 return SimpleAttributeSet.EMPTY;
321 }
322 CssParser parser = new CssParser();
323 return parser.parseDeclaration(decl);
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337 public void loadRules(Reader in, URL ref) throws IOException {
338 CssParser parser = new CssParser();
339 parser.parse(ref, in, false, false);
340 }
341
342
343
344
345
346
347 public AttributeSet getViewAttributes(View v) {
348 return new ViewAttributeSet(v);
349 }
350
351
352
353
354
355
356 public void removeStyle(String nm) {
357 Style aStyle = getStyle(nm);
358
359 if (aStyle != null) {
360 String selector = cleanSelectorString(nm);
361 String[] selectors = getSimpleSelectors(selector);
362 synchronized(this) {
363 SelectorMapping mapping = getRootSelectorMapping();
364 for (int i = selectors.length - 1; i >= 0; i--) {
365 mapping = mapping.getChildSelectorMapping(selectors[i],
366 true);
367 }
368 Style rule = mapping.getStyle();
369 if (rule != null) {
370 mapping.setStyle(null);
371 if (resolvedStyles.size() > 0) {
372 Enumeration<ResolvedStyle> values = resolvedStyles.elements();
373 while (values.hasMoreElements()) {
374 ResolvedStyle style = values.nextElement();
375 style.removeStyle(rule);
376 }
377 }
378 }
379 }
380 }
381 super.removeStyle(nm);
382 }
383
384
385
386
387
388
389
390
391
392 public void addStyleSheet(StyleSheet ss) {
393 synchronized(this) {
394 if (linkedStyleSheets == null) {
395 linkedStyleSheets = new Vector<StyleSheet>();
396 }
397 if (!linkedStyleSheets.contains(ss)) {
398 int index = 0;
399 if (ss instanceof javax.swing.plaf.UIResource
400 && linkedStyleSheets.size() > 1) {
401 index = linkedStyleSheets.size() - 1;
402 }
403 linkedStyleSheets.insertElementAt(ss, index);
404 linkStyleSheetAt(ss, index);
405 }
406 }
407 }
408
409
410
411
412
413
414 public void removeStyleSheet(StyleSheet ss) {
415 synchronized(this) {
416 if (linkedStyleSheets != null) {
417 int index = linkedStyleSheets.indexOf(ss);
418 if (index != -1) {
419 linkedStyleSheets.removeElementAt(index);
420 unlinkStyleSheet(ss, index);
421 if (index == 0 && linkedStyleSheets.size() == 0) {
422 linkedStyleSheets = null;
423 }
424 }
425 }
426 }
427 }
428
429
430
431
432
433
434
435
436
437
438
439 public StyleSheet[] getStyleSheets() {
440 StyleSheet[] retValue;
441
442 synchronized(this) {
443 if (linkedStyleSheets != null) {
444 retValue = new StyleSheet[linkedStyleSheets.size()];
445 linkedStyleSheets.copyInto(retValue);
446 }
447 else {
448 retValue = null;
449 }
450 }
451 return retValue;
452 }
453
454
455
456
457
458
459
460
461
462 public void importStyleSheet(URL url) {
463 try {
464 InputStream is;
465
466 is = url.openStream();
467 Reader r = new BufferedReader(new InputStreamReader(is));
468 CssParser parser = new CssParser();
469 parser.parse(url, r, false, true);
470 r.close();
471 is.close();
472 } catch (Throwable e) {
473
474
475 }
476 }
477
478
479
480
481
482
483
484 public void setBase(URL base) {
485 this.base = base;
486 }
487
488
489
490
491
492
493 public URL getBase() {
494 return base;
495 }
496
497
498
499
500
501
502 public void addCSSAttribute(MutableAttributeSet attr, CSS.Attribute key,
503 String value) {
504 css.addInternalCSSValue(attr, key, value);
505 }
506
507
508
509
510
511
512 public boolean addCSSAttributeFromHTML(MutableAttributeSet attr,
513 CSS.Attribute key, String value) {
514 Object iValue = css.getCssValue(key, value);
515 if (iValue != null) {
516 attr.addAttribute(key, iValue);
517 return true;
518 }
519 return false;
520 }
521
522
523
524
525
526
527
528
529
530 public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) {
531 AttributeSet cssAttrSet = css.translateHTMLToCSS(htmlAttrSet);
532
533 MutableAttributeSet cssStyleSet = addStyle(null, null);
534 cssStyleSet.addAttributes(cssAttrSet);
535
536 return cssStyleSet;
537 }
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553 public AttributeSet addAttribute(AttributeSet old, Object key,
554 Object value) {
555 if (css == null) {
556
557
558 css = new CSS();
559 }
560 if (key instanceof StyleConstants) {
561 HTML.Tag tag = HTML.getTagForStyleConstantsKey(
562 (StyleConstants)key);
563
564 if (tag != null && old.isDefined(tag)) {
565 old = removeAttribute(old, tag);
566 }
567
568 Object cssValue = css.styleConstantsValueToCSSValue
569 ((StyleConstants)key, value);
570 if (cssValue != null) {
571 Object cssKey = css.styleConstantsKeyToCSSKey
572 ((StyleConstants)key);
573 if (cssKey != null) {
574 return super.addAttribute(old, cssKey, cssValue);
575 }
576 }
577 }
578 return super.addAttribute(old, key, value);
579 }
580
581
582
583
584
585
586
587
588
589
590
591 public AttributeSet addAttributes(AttributeSet old, AttributeSet attr) {
592 if (!(attr instanceof HTMLDocument.TaggedAttributeSet)) {
593 old = removeHTMLTags(old, attr);
594 }
595 return super.addAttributes(old, convertAttributeSet(attr));
596 }
597
598
599
600
601
602
603
604
605
606
607
608 public AttributeSet removeAttribute(AttributeSet old, Object key) {
609 if (key instanceof StyleConstants) {
610 HTML.Tag tag = HTML.getTagForStyleConstantsKey(
611 (StyleConstants)key);
612 if (tag != null) {
613 old = super.removeAttribute(old, tag);
614 }
615
616 Object cssKey = css.styleConstantsKeyToCSSKey((StyleConstants)key);
617 if (cssKey != null) {
618 return super.removeAttribute(old, cssKey);
619 }
620 }
621 return super.removeAttribute(old, key);
622 }
623
624
625
626
627
628
629
630
631
632
633
634 public AttributeSet removeAttributes(AttributeSet old, Enumeration<?> names) {
635
636
637
638 return super.removeAttributes(old, names);
639 }
640
641
642
643
644
645
646
647
648
649
650
651 public AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs) {
652 if (old != attrs) {
653 old = removeHTMLTags(old, attrs);
654 }
655 return super.removeAttributes(old, convertAttributeSet(attrs));
656 }
657
658
659
660
661
662
663
664
665
666
667
668 protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) {
669 return new SmallConversionSet(a);
670 }
671
672
673
674
675
676
677
678
679
680
681
682
683
684 protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) {
685 return new LargeConversionSet(a);
686 }
687
688
689
690
691
692 private AttributeSet removeHTMLTags(AttributeSet old, AttributeSet attr) {
693 if (!(attr instanceof LargeConversionSet) &&
694 !(attr instanceof SmallConversionSet)) {
695 Enumeration names = attr.getAttributeNames();
696
697 while (names.hasMoreElements()) {
698 Object key = names.nextElement();
699
700 if (key instanceof StyleConstants) {
701 HTML.Tag tag = HTML.getTagForStyleConstantsKey(
702 (StyleConstants)key);
703
704 if (tag != null && old.isDefined(tag)) {
705 old = super.removeAttribute(old, tag);
706 }
707 }
708 }
709 }
710 return old;
711 }
712
713
714
715
716
717
718
719 AttributeSet convertAttributeSet(AttributeSet a) {
720 if ((a instanceof LargeConversionSet) ||
721 (a instanceof SmallConversionSet)) {
722
723 return a;
724 }
725
726
727
728 Enumeration names = a.getAttributeNames();
729 while (names.hasMoreElements()) {
730 Object name = names.nextElement();
731 if (name instanceof StyleConstants) {
732
733
734 MutableAttributeSet converted = new LargeConversionSet();
735 Enumeration keys = a.getAttributeNames();
736 while (keys.hasMoreElements()) {
737 Object key = keys.nextElement();
738 Object cssValue = null;
739 if (key instanceof StyleConstants) {
740
741 Object cssKey = css.styleConstantsKeyToCSSKey
742 ((StyleConstants)key);
743 if (cssKey != null) {
744 Object value = a.getAttribute(key);
745 cssValue = css.styleConstantsValueToCSSValue
746 ((StyleConstants)key, value);
747 if (cssValue != null) {
748 converted.addAttribute(cssKey, cssValue);
749 }
750 }
751 }
752 if (cssValue == null) {
753 converted.addAttribute(key, a.getAttribute(key));
754 }
755 }
756 return converted;
757 }
758 }
759 return a;
760 }
761
762
763
764
765
766 class LargeConversionSet extends SimpleAttributeSet {
767
768
769
770
771
772
773 public LargeConversionSet(AttributeSet source) {
774 super(source);
775 }
776
777 public LargeConversionSet() {
778 super();
779 }
780
781
782
783
784
785
786
787
788 public boolean isDefined(Object key) {
789 if (key instanceof StyleConstants) {
790 Object cssKey = css.styleConstantsKeyToCSSKey
791 ((StyleConstants)key);
792 if (cssKey != null) {
793 return super.isDefined(cssKey);
794 }
795 }
796 return super.isDefined(key);
797 }
798
799
800
801
802
803
804
805
806 public Object getAttribute(Object key) {
807 if (key instanceof StyleConstants) {
808 Object cssKey = css.styleConstantsKeyToCSSKey
809 ((StyleConstants)key);
810 if (cssKey != null) {
811 Object value = super.getAttribute(cssKey);
812 if (value != null) {
813 return css.cssValueToStyleConstantsValue
814 ((StyleConstants)key, value);
815 }
816 }
817 }
818 return super.getAttribute(key);
819 }
820 }
821
822
823
824
825
826 class SmallConversionSet extends SmallAttributeSet {
827
828
829
830
831
832
833 public SmallConversionSet(AttributeSet attrs) {
834 super(attrs);
835 }
836
837
838
839
840
841
842
843
844 public boolean isDefined(Object key) {
845 if (key instanceof StyleConstants) {
846 Object cssKey = css.styleConstantsKeyToCSSKey
847 ((StyleConstants)key);
848 if (cssKey != null) {
849 return super.isDefined(cssKey);
850 }
851 }
852 return super.isDefined(key);
853 }
854
855
856
857
858
859
860
861
862 public Object getAttribute(Object key) {
863 if (key instanceof StyleConstants) {
864 Object cssKey = css.styleConstantsKeyToCSSKey
865 ((StyleConstants)key);
866 if (cssKey != null) {
867 Object value = super.getAttribute(cssKey);
868 if (value != null) {
869 return css.cssValueToStyleConstantsValue
870 ((StyleConstants)key, value);
871 }
872 }
873 }
874 return super.getAttribute(key);
875 }
876 }
877
878
879
880
881
882
883 public Font getFont(AttributeSet a) {
884 return css.getFont(this, a, 12, this);
885 }
886
887
888
889
890
891
892
893
894
895 public Color getForeground(AttributeSet a) {
896 Color c = css.getColor(a, CSS.Attribute.COLOR);
897 if (c == null) {
898 return Color.black;
899 }
900 return c;
901 }
902
903
904
905
906
907
908
909
910
911 public Color getBackground(AttributeSet a) {
912 return css.getColor(a, CSS.Attribute.BACKGROUND_COLOR);
913 }
914
915
916
917
918
919 public BoxPainter getBoxPainter(AttributeSet a) {
920 return new BoxPainter(a, css, this);
921 }
922
923
924
925
926
927 public ListPainter getListPainter(AttributeSet a) {
928 return new ListPainter(a, this);
929 }
930
931
932
933
934 public void setBaseFontSize(int sz) {
935 css.setBaseFontSize(sz);
936 }
937
938
939
940
941
942
943 public void setBaseFontSize(String size) {
944 css.setBaseFontSize(size);
945 }
946
947 public static int getIndexOfSize(float pt) {
948 return CSS.getIndexOfSize(pt, sizeMapDefault);
949 }
950
951
952
953
954 public float getPointSize(int index) {
955 return css.getPointSize(index, this);
956 }
957
958
959
960
961
962 public float getPointSize(String size) {
963 return css.getPointSize(size, this);
964 }
965
966
967
968
969
970
971
972 public Color stringToColor(String string) {
973 return CSS.stringToColor(string);
974 }
975
976
977
978
979
980 ImageIcon getBackgroundImage(AttributeSet attr) {
981 Object value = attr.getAttribute(CSS.Attribute.BACKGROUND_IMAGE);
982
983 if (value != null) {
984 return ((CSS.BackgroundImage)value).getImage(getBase());
985 }
986 return null;
987 }
988
989
990
991
992
993
994
995
996
997
998 void addRule(String[] selector, AttributeSet declaration,
999 boolean isLinked) {
1000 int n = selector.length;
1001 StringBuilder sb = new StringBuilder();
1002 sb.append(selector[0]);
1003 for (int counter = 1; counter < n; counter++) {
1004 sb.append(' ');
1005 sb.append(selector[counter]);
1006 }
1007 String selectorName = sb.toString();
1008 Style rule = getStyle(selectorName);
1009 if (rule == null) {
1010
1011
1012
1013
1014
1015 Style altRule = addStyle(selectorName, null);
1016 synchronized(this) {
1017 SelectorMapping mapping = getRootSelectorMapping();
1018 for (int i = n - 1; i >= 0; i--) {
1019 mapping = mapping.getChildSelectorMapping
1020 (selector[i], true);
1021 }
1022 rule = mapping.getStyle();
1023 if (rule == null) {
1024 rule = altRule;
1025 mapping.setStyle(rule);
1026 refreshResolvedRules(selectorName, selector, rule,
1027 mapping.getSpecificity());
1028 }
1029 }
1030 }
1031 if (isLinked) {
1032 rule = getLinkedStyle(rule);
1033 }
1034 rule.addAttributes(declaration);
1035 }
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 private synchronized void linkStyleSheetAt(StyleSheet ss, int index) {
1047 if (resolvedStyles.size() > 0) {
1048 Enumeration<ResolvedStyle> values = resolvedStyles.elements();
1049 while (values.hasMoreElements()) {
1050 ResolvedStyle rule = values.nextElement();
1051 rule.insertExtendedStyleAt(ss.getRule(rule.getName()),
1052 index);
1053 }
1054 }
1055 }
1056
1057
1058
1059
1060
1061
1062 private synchronized void unlinkStyleSheet(StyleSheet ss, int index) {
1063 if (resolvedStyles.size() > 0) {
1064 Enumeration<ResolvedStyle> values = resolvedStyles.elements();
1065 while (values.hasMoreElements()) {
1066 ResolvedStyle rule = values.nextElement();
1067 rule.removeExtendedStyleAt(index);
1068 }
1069 }
1070 }
1071
1072
1073
1074
1075
1076 String[] getSimpleSelectors(String selector) {
1077 selector = cleanSelectorString(selector);
1078 SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
1079 Vector<String> selectors = sb.getVector();
1080 int lastIndex = 0;
1081 int length = selector.length();
1082 while (lastIndex != -1) {
1083 int newIndex = selector.indexOf(' ', lastIndex);
1084 if (newIndex != -1) {
1085 selectors.addElement(selector.substring(lastIndex, newIndex));
1086 if (++newIndex == length) {
1087 lastIndex = -1;
1088 }
1089 else {
1090 lastIndex = newIndex;
1091 }
1092 }
1093 else {
1094 selectors.addElement(selector.substring(lastIndex));
1095 lastIndex = -1;
1096 }
1097 }
1098 String[] retValue = new String[selectors.size()];
1099 selectors.copyInto(retValue);
1100 SearchBuffer.releaseSearchBuffer(sb);
1101 return retValue;
1102 }
1103
1104
1105
1106
1107
1108 String cleanSelectorString(String selector) {
1109 boolean lastWasSpace = true;
1110 for (int counter = 0, maxCounter = selector.length();
1111 counter < maxCounter; counter++) {
1112 switch(selector.charAt(counter)) {
1113 case ' ':
1114 if (lastWasSpace) {
1115 return _cleanSelectorString(selector);
1116 }
1117 lastWasSpace = true;
1118 break;
1119 case '\n':
1120 case '\r':
1121 case '\t':
1122 return _cleanSelectorString(selector);
1123 default:
1124 lastWasSpace = false;
1125 }
1126 }
1127 if (lastWasSpace) {
1128 return _cleanSelectorString(selector);
1129 }
1130
1131 return selector;
1132 }
1133
1134
1135
1136
1137
1138 private String _cleanSelectorString(String selector) {
1139 SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
1140 StringBuffer buff = sb.getStringBuffer();
1141 boolean lastWasSpace = true;
1142 int lastIndex = 0;
1143 char[] chars = selector.toCharArray();
1144 int numChars = chars.length;
1145 String retValue = null;
1146 try {
1147 for (int counter = 0; counter < numChars; counter++) {
1148 switch(chars[counter]) {
1149 case ' ':
1150 if (!lastWasSpace) {
1151 lastWasSpace = true;
1152 if (lastIndex < counter) {
1153 buff.append(chars, lastIndex,
1154 1 + counter - lastIndex);
1155 }
1156 }
1157 lastIndex = counter + 1;
1158 break;
1159 case '\n':
1160 case '\r':
1161 case '\t':
1162 if (!lastWasSpace) {
1163 lastWasSpace = true;
1164 if (lastIndex < counter) {
1165 buff.append(chars, lastIndex,
1166 counter - lastIndex);
1167 buff.append(' ');
1168 }
1169 }
1170 lastIndex = counter + 1;
1171 break;
1172 default:
1173 lastWasSpace = false;
1174 break;
1175 }
1176 }
1177 if (lastWasSpace && buff.length() > 0) {
1178
1179 buff.setLength(buff.length() - 1);
1180 }
1181 else if (lastIndex < numChars) {
1182 buff.append(chars, lastIndex, numChars - lastIndex);
1183 }
1184 retValue = buff.toString();
1185 }
1186 finally {
1187 SearchBuffer.releaseSearchBuffer(sb);
1188 }
1189 return retValue;
1190 }
1191
1192
1193
1194
1195
1196 private SelectorMapping getRootSelectorMapping() {
1197 return selectorMapping;
1198 }
1199
1200
1201
1202
1203
1204
1205
1206
1207 static int getSpecificity(String selector) {
1208 int specificity = 0;
1209 boolean lastWasSpace = true;
1210
1211 for (int counter = 0, maxCounter = selector.length();
1212 counter < maxCounter; counter++) {
1213 switch(selector.charAt(counter)) {
1214 case '.':
1215 specificity += 100;
1216 break;
1217 case '#':
1218 specificity += 10000;
1219 break;
1220 case ' ':
1221 lastWasSpace = true;
1222 break;
1223 default:
1224 if (lastWasSpace) {
1225 lastWasSpace = false;
1226 specificity += 1;
1227 }
1228 }
1229 }
1230 return specificity;
1231 }
1232
1233
1234
1235
1236
1237 private Style getLinkedStyle(Style localStyle) {
1238
1239
1240
1241
1242
1243
1244 Style retStyle = (Style)localStyle.getResolveParent();
1245 if (retStyle == null) {
1246 retStyle = addStyle(null, null);
1247 localStyle.setResolveParent(retStyle);
1248 }
1249 return retStyle;
1250 }
1251
1252
1253
1254
1255
1256 private synchronized Style getResolvedStyle(String selector,
1257 Vector elements,
1258 HTML.Tag t) {
1259 Style retStyle = resolvedStyles.get(selector);
1260 if (retStyle == null) {
1261 retStyle = createResolvedStyle(selector, elements, t);
1262 }
1263 return retStyle;
1264 }
1265
1266
1267
1268
1269
1270 private synchronized Style getResolvedStyle(String selector) {
1271 Style retStyle = resolvedStyles.get(selector);
1272 if (retStyle == null) {
1273 retStyle = createResolvedStyle(selector);
1274 }
1275 return retStyle;
1276 }
1277
1278
1279
1280
1281
1282
1283 private void addSortedStyle(SelectorMapping mapping, Vector<SelectorMapping> elements) {
1284 int size = elements.size();
1285
1286 if (size > 0) {
1287 int specificity = mapping.getSpecificity();
1288
1289 for (int counter = 0; counter < size; counter++) {
1290 if (specificity >= elements.elementAt(counter).getSpecificity()) {
1291 elements.insertElementAt(mapping, counter);
1292 return;
1293 }
1294 }
1295 }
1296 elements.addElement(mapping);
1297 }
1298
1299
1300
1301
1302
1303
1304 private synchronized void getStyles(SelectorMapping parentMapping,
1305 Vector<SelectorMapping> styles,
1306 String[] tags, String[] ids, String[] classes,
1307 int index, int numElements,
1308 Hashtable<SelectorMapping, SelectorMapping> alreadyChecked) {
1309
1310 if (alreadyChecked.contains(parentMapping)) {
1311 return;
1312 }
1313 alreadyChecked.put(parentMapping, parentMapping);
1314 Style style = parentMapping.getStyle();
1315 if (style != null) {
1316 addSortedStyle(parentMapping, styles);
1317 }
1318 for (int counter = index; counter < numElements; counter++) {
1319 String tagString = tags[counter];
1320 if (tagString != null) {
1321 SelectorMapping childMapping = parentMapping.
1322 getChildSelectorMapping(tagString, false);
1323 if (childMapping != null) {
1324 getStyles(childMapping, styles, tags, ids, classes,
1325 counter + 1, numElements, alreadyChecked);
1326 }
1327 if (classes[counter] != null) {
1328 String className = classes[counter];
1329 childMapping = parentMapping.getChildSelectorMapping(
1330 tagString + "." + className, false);
1331 if (childMapping != null) {
1332 getStyles(childMapping, styles, tags, ids, classes,
1333 counter + 1, numElements, alreadyChecked);
1334 }
1335 childMapping = parentMapping.getChildSelectorMapping(
1336 "." + className, false);
1337 if (childMapping != null) {
1338 getStyles(childMapping, styles, tags, ids, classes,
1339 counter + 1, numElements, alreadyChecked);
1340 }
1341 }
1342 if (ids[counter] != null) {
1343 String idName = ids[counter];
1344 childMapping = parentMapping.getChildSelectorMapping(
1345 tagString + "#" + idName, false);
1346 if (childMapping != null) {
1347 getStyles(childMapping, styles, tags, ids, classes,
1348 counter + 1, numElements, alreadyChecked);
1349 }
1350 childMapping = parentMapping.getChildSelectorMapping(
1351 "#" + idName, false);
1352 if (childMapping != null) {
1353 getStyles(childMapping, styles, tags, ids, classes,
1354 counter + 1, numElements, alreadyChecked);
1355 }
1356 }
1357 }
1358 }
1359 }
1360
1361
1362
1363
1364
1365 private synchronized Style createResolvedStyle(String selector,
1366 String[] tags,
1367 String[] ids, String[] classes) {
1368 SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
1369 Vector<SelectorMapping> tempVector = sb.getVector();
1370 Hashtable<SelectorMapping, SelectorMapping> tempHashtable = sb.getHashtable();
1371
1372
1373 try {
1374 SelectorMapping mapping = getRootSelectorMapping();
1375 int numElements = tags.length;
1376 String tagString = tags[0];
1377 SelectorMapping childMapping = mapping.getChildSelectorMapping(
1378 tagString, false);
1379 if (childMapping != null) {
1380 getStyles(childMapping, tempVector, tags, ids, classes, 1,
1381 numElements, tempHashtable);
1382 }
1383 if (classes[0] != null) {
1384 String className = classes[0];
1385 childMapping = mapping.getChildSelectorMapping(
1386 tagString + "." + className, false);
1387 if (childMapping != null) {
1388 getStyles(childMapping, tempVector, tags, ids, classes, 1,
1389 numElements, tempHashtable);
1390 }
1391 childMapping = mapping.getChildSelectorMapping(
1392 "." + className, false);
1393 if (childMapping != null) {
1394 getStyles(childMapping, tempVector, tags, ids, classes,
1395 1, numElements, tempHashtable);
1396 }
1397 }
1398 if (ids[0] != null) {
1399 String idName = ids[0];
1400 childMapping = mapping.getChildSelectorMapping(
1401 tagString + "#" + idName, false);
1402 if (childMapping != null) {
1403 getStyles(childMapping, tempVector, tags, ids, classes,
1404 1, numElements, tempHashtable);
1405 }
1406 childMapping = mapping.getChildSelectorMapping(
1407 "#" + idName, false);
1408 if (childMapping != null) {
1409 getStyles(childMapping, tempVector, tags, ids, classes,
1410 1, numElements, tempHashtable);
1411 }
1412 }
1413
1414
1415 int numLinkedSS = (linkedStyleSheets != null) ?
1416 linkedStyleSheets.size() : 0;
1417 int numStyles = tempVector.size();
1418 AttributeSet[] attrs = new AttributeSet[numStyles + numLinkedSS];
1419 for (int counter = 0; counter < numStyles; counter++) {
1420 attrs[counter] = tempVector.elementAt(counter).getStyle();
1421 }
1422
1423 for (int counter = 0; counter < numLinkedSS; counter++) {
1424 AttributeSet attr = linkedStyleSheets.elementAt(counter).getRule(selector);
1425 if (attr == null) {
1426 attrs[counter + numStyles] = SimpleAttributeSet.EMPTY;
1427 }
1428 else {
1429 attrs[counter + numStyles] = attr;
1430 }
1431 }
1432 ResolvedStyle retStyle = new ResolvedStyle(selector, attrs,
1433 numStyles);
1434 resolvedStyles.put(selector, retStyle);
1435 return retStyle;
1436 }
1437 finally {
1438 SearchBuffer.releaseSearchBuffer(sb);
1439 }
1440 }
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453 private Style createResolvedStyle(String selector, Vector elements,
1454 HTML.Tag t) {
1455 int numElements = elements.size();
1456
1457
1458 String tags[] = new String[numElements];
1459 String ids[] = new String[numElements];
1460 String classes[] = new String[numElements];
1461 for (int counter = 0; counter < numElements; counter++) {
1462 Element e = (Element)elements.elementAt(counter);
1463 AttributeSet attr = e.getAttributes();
1464 if (counter == 0 && e.isLeaf()) {
1465
1466 Object testAttr = attr.getAttribute(t);
1467 if (testAttr instanceof AttributeSet) {
1468 attr = (AttributeSet)testAttr;
1469 }
1470 else {
1471 attr = null;
1472 }
1473 }
1474 if (attr != null) {
1475 HTML.Tag tag = (HTML.Tag)attr.getAttribute(StyleConstants.
1476 NameAttribute);
1477 if (tag != null) {
1478 tags[counter] = tag.toString();
1479 }
1480 else {
1481 tags[counter] = null;
1482 }
1483 if (attr.isDefined(HTML.Attribute.CLASS)) {
1484 classes[counter] = attr.getAttribute
1485 (HTML.Attribute.CLASS).toString();
1486 }
1487 else {
1488 classes[counter] = null;
1489 }
1490 if (attr.isDefined(HTML.Attribute.ID)) {
1491 ids[counter] = attr.getAttribute(HTML.Attribute.ID).
1492 toString();
1493 }
1494 else {
1495 ids[counter] = null;
1496 }
1497 }
1498 else {
1499 tags[counter] = ids[counter] = classes[counter] = null;
1500 }
1501 }
1502 tags[0] = t.toString();
1503 return createResolvedStyle(selector, tags, ids, classes);
1504 }
1505
1506
1507
1508
1509
1510
1511 private Style createResolvedStyle(String selector) {
1512 SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
1513
1514 Vector<String> elements = sb.getVector();
1515 try {
1516 boolean done;
1517 int dotIndex = 0;
1518 int spaceIndex;
1519 int poundIndex = 0;
1520 int lastIndex = 0;
1521 int length = selector.length();
1522 while (lastIndex < length) {
1523 if (dotIndex == lastIndex) {
1524 dotIndex = selector.indexOf('.', lastIndex);
1525 }
1526 if (poundIndex == lastIndex) {
1527 poundIndex = selector.indexOf('#', lastIndex);
1528 }
1529 spaceIndex = selector.indexOf(' ', lastIndex);
1530 if (spaceIndex == -1) {
1531 spaceIndex = length;
1532 }
1533 if (dotIndex != -1 && poundIndex != -1 &&
1534 dotIndex < spaceIndex && poundIndex < spaceIndex) {
1535 if (poundIndex < dotIndex) {
1536
1537 if (lastIndex == poundIndex) {
1538 elements.addElement("");
1539 }
1540 else {
1541 elements.addElement(selector.substring(lastIndex,
1542 poundIndex));
1543 }
1544 if ((dotIndex + 1) < spaceIndex) {
1545 elements.addElement(selector.substring
1546 (dotIndex + 1, spaceIndex));
1547 }
1548 else {
1549 elements.addElement(null);
1550 }
1551 if ((poundIndex + 1) == dotIndex) {
1552 elements.addElement(null);
1553 }
1554 else {
1555 elements.addElement(selector.substring
1556 (poundIndex + 1, dotIndex));
1557 }
1558 }
1559 else if(poundIndex < spaceIndex) {
1560
1561 if (lastIndex == dotIndex) {
1562 elements.addElement("");
1563 }
1564 else {
1565 elements.addElement(selector.substring(lastIndex,
1566 dotIndex));
1567 }
1568 if ((dotIndex + 1) < poundIndex) {
1569 elements.addElement(selector.substring
1570 (dotIndex + 1, poundIndex));
1571 }
1572 else {
1573 elements.addElement(null);
1574 }
1575 if ((poundIndex + 1) == spaceIndex) {
1576 elements.addElement(null);
1577 }
1578 else {
1579 elements.addElement(selector.substring
1580 (poundIndex + 1, spaceIndex));
1581 }
1582 }
1583 dotIndex = poundIndex = spaceIndex + 1;
1584 }
1585 else if (dotIndex != -1 && dotIndex < spaceIndex) {
1586
1587 if (dotIndex == lastIndex) {
1588 elements.addElement("");
1589 }
1590 else {
1591 elements.addElement(selector.substring(lastIndex,
1592 dotIndex));
1593 }
1594 if ((dotIndex + 1) == spaceIndex) {
1595 elements.addElement(null);
1596 }
1597 else {
1598 elements.addElement(selector.substring(dotIndex + 1,
1599 spaceIndex));
1600 }
1601 elements.addElement(null);
1602 dotIndex = spaceIndex + 1;
1603 }
1604 else if (poundIndex != -1 && poundIndex < spaceIndex) {
1605
1606 if (poundIndex == lastIndex) {
1607 elements.addElement("");
1608 }
1609 else {
1610 elements.addElement(selector.substring(lastIndex,
1611 poundIndex));
1612 }
1613 elements.addElement(null);
1614 if ((poundIndex + 1) == spaceIndex) {
1615 elements.addElement(null);
1616 }
1617 else {
1618 elements.addElement(selector.substring(poundIndex + 1,
1619 spaceIndex));
1620 }
1621 poundIndex = spaceIndex + 1;
1622 }
1623 else {
1624
1625 elements.addElement(selector.substring(lastIndex,
1626 spaceIndex));
1627 elements.addElement(null);
1628 elements.addElement(null);
1629 }
1630 lastIndex = spaceIndex + 1;
1631 }
1632
1633 int total = elements.size();
1634 int numTags = total / 3;
1635 String[] tags = new String[numTags];
1636 String[] ids = new String[numTags];
1637 String[] classes = new String[numTags];
1638 for (int index = 0, eIndex = total - 3; index < numTags;
1639 index++, eIndex -= 3) {
1640 tags[index] = elements.elementAt(eIndex);
1641 classes[index] = elements.elementAt(eIndex + 1);
1642 ids[index] = elements.elementAt(eIndex + 2);
1643 }
1644 return createResolvedStyle(selector, tags, ids, classes);
1645 }
1646 finally {
1647 SearchBuffer.releaseSearchBuffer(sb);
1648 }
1649 }
1650
1651
1652
1653
1654
1655
1656 private synchronized void refreshResolvedRules(String selectorName,
1657 String[] selector,
1658 Style newStyle,
1659 int specificity) {
1660 if (resolvedStyles.size() > 0) {
1661 Enumeration<ResolvedStyle> values = resolvedStyles.elements();
1662 while (values.hasMoreElements()) {
1663 ResolvedStyle style = values.nextElement();
1664 if (style.matches(selectorName)) {
1665 style.insertStyle(newStyle, specificity);
1666 }
1667 }
1668 }
1669 }
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679 private static class SearchBuffer {
1680
1681
1682 static Stack<SearchBuffer> searchBuffers = new Stack<SearchBuffer>();
1683
1684 Vector vector = null;
1685 StringBuffer stringBuffer = null;
1686 Hashtable hashtable = null;
1687
1688
1689
1690
1691
1692 static SearchBuffer obtainSearchBuffer() {
1693 SearchBuffer sb;
1694 try {
1695 if(!searchBuffers.empty()) {
1696 sb = searchBuffers.pop();
1697 } else {
1698 sb = new SearchBuffer();
1699 }
1700 } catch (EmptyStackException ese) {
1701 sb = new SearchBuffer();
1702 }
1703 return sb;
1704 }
1705
1706
1707
1708
1709
1710 static void releaseSearchBuffer(SearchBuffer sb) {
1711 sb.empty();
1712 searchBuffers.push(sb);
1713 }
1714
1715 StringBuffer getStringBuffer() {
1716 if (stringBuffer == null) {
1717 stringBuffer = new StringBuffer();
1718 }
1719 return stringBuffer;
1720 }
1721
1722 Vector getVector() {
1723 if (vector == null) {
1724 vector = new Vector();
1725 }
1726 return vector;
1727 }
1728
1729 Hashtable getHashtable() {
1730 if (hashtable == null) {
1731 hashtable = new Hashtable();
1732 }
1733 return hashtable;
1734 }
1735
1736 void empty() {
1737 if (stringBuffer != null) {
1738 stringBuffer.setLength(0);
1739 }
1740 if (vector != null) {
1741 vector.removeAllElements();
1742 }
1743 if (hashtable != null) {
1744 hashtable.clear();
1745 }
1746 }
1747 }
1748
1749
1750 static final Border noBorder = new EmptyBorder(0,0,0,0);
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763 public static class BoxPainter implements Serializable {
1764
1765 BoxPainter(AttributeSet a, CSS css, StyleSheet ss) {
1766 this.ss = ss;
1767 this.css = css;
1768 border = getBorder(a);
1769 binsets = border.getBorderInsets(null);
1770 topMargin = getLength(CSS.Attribute.MARGIN_TOP, a);
1771 bottomMargin = getLength(CSS.Attribute.MARGIN_BOTTOM, a);
1772 leftMargin = getLength(CSS.Attribute.MARGIN_LEFT, a);
1773 rightMargin = getLength(CSS.Attribute.MARGIN_RIGHT, a);
1774 bg = ss.getBackground(a);
1775 if (ss.getBackgroundImage(a) != null) {
1776 bgPainter = new BackgroundImagePainter(a, css, ss);
1777 }
1778 }
1779
1780
1781
1782
1783
1784
1785 Border getBorder(AttributeSet a) {
1786 return new CSSBorder(a);
1787 }
1788
1789
1790
1791
1792
1793
1794
1795 Color getBorderColor(AttributeSet a) {
1796 Color color = css.getColor(a, CSS.Attribute.BORDER_COLOR);
1797 if (color == null) {
1798 color = css.getColor(a, CSS.Attribute.COLOR);
1799 if (color == null) {
1800 return Color.black;
1801 }
1802 }
1803 return color;
1804 }
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818 public float getInset(int side, View v) {
1819 AttributeSet a = v.getAttributes();
1820 float inset = 0;
1821 switch(side) {
1822 case View.LEFT:
1823 inset += getOrientationMargin(HorizontalMargin.LEFT,
1824 leftMargin, a, isLeftToRight(v));
1825 inset += binsets.left;
1826 inset += getLength(CSS.Attribute.PADDING_LEFT, a);
1827 break;
1828 case View.RIGHT:
1829 inset += getOrientationMargin(HorizontalMargin.RIGHT,
1830 rightMargin, a, isLeftToRight(v));
1831 inset += binsets.right;
1832 inset += getLength(CSS.Attribute.PADDING_RIGHT, a);
1833 break;
1834 case View.TOP:
1835 inset += topMargin;
1836 inset += binsets.top;
1837 inset += getLength(CSS.Attribute.PADDING_TOP, a);
1838 break;
1839 case View.BOTTOM:
1840 inset += bottomMargin;
1841 inset += binsets.bottom;
1842 inset += getLength(CSS.Attribute.PADDING_BOTTOM, a);
1843 break;
1844 default:
1845 throw new IllegalArgumentException("Invalid side: " + side);
1846 }
1847 return inset;
1848 }
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866 public void paint(Graphics g, float x, float y, float w, float h, View v) {
1867
1868
1869
1870
1871 float dx = 0;
1872 float dy = 0;
1873 float dw = 0;
1874 float dh = 0;
1875 AttributeSet a = v.getAttributes();
1876 boolean isLeftToRight = isLeftToRight(v);
1877 float localLeftMargin = getOrientationMargin(HorizontalMargin.LEFT,
1878 leftMargin,
1879 a, isLeftToRight);
1880 float localRightMargin = getOrientationMargin(HorizontalMargin.RIGHT,
1881 rightMargin,
1882 a, isLeftToRight);
1883 if (!(v instanceof HTMLEditorKit.HTMLFactory.BodyBlockView)) {
1884 dx = localLeftMargin;
1885 dy = topMargin;
1886 dw = -(localLeftMargin + localRightMargin);
1887 dh = -(topMargin + bottomMargin);
1888 }
1889 if (bg != null) {
1890 g.setColor(bg);
1891 g.fillRect((int) (x + dx),
1892 (int) (y + dy),
1893 (int) (w + dw),
1894 (int) (h + dh));
1895 }
1896 if (bgPainter != null) {
1897 bgPainter.paint(g, x + dx, y + dy, w + dw, h + dh, v);
1898 }
1899 x += localLeftMargin;
1900 y += topMargin;
1901 w -= localLeftMargin + localRightMargin;
1902 h -= topMargin + bottomMargin;
1903 if (border instanceof BevelBorder) {
1904
1905 int bw = (int) getLength(CSS.Attribute.BORDER_TOP_WIDTH, a);
1906 for (int i = bw - 1; i >= 0; i--) {
1907 border.paintBorder(null, g, (int) x + i, (int) y + i,
1908 (int) w - 2 * i, (int) h - 2 * i);
1909 }
1910 } else {
1911 border.paintBorder(null, g, (int) x, (int) y, (int) w, (int) h);
1912 }
1913 }
1914
1915 float getLength(CSS.Attribute key, AttributeSet a) {
1916 return css.getLength(a, key, ss);
1917 }
1918
1919 static boolean isLeftToRight(View v) {
1920 boolean ret = true;
1921 if (isOrientationAware(v)) {
1922 Container container;
1923 if (v != null && (container = v.getContainer()) != null) {
1924 ret = container.getComponentOrientation().isLeftToRight();
1925 }
1926 }
1927 return ret;
1928 }
1929
1930
1931
1932
1933
1934
1935
1936 static boolean isOrientationAware(View v) {
1937 boolean ret = false;
1938 AttributeSet attr;
1939 Object obj;
1940 if (v != null
1941 && (attr = v.getElement().getAttributes()) != null
1942 && (obj = attr.getAttribute(StyleConstants.NameAttribute)) instanceof HTML.Tag
1943 && (obj == HTML.Tag.DIR
1944 || obj == HTML.Tag.MENU
1945 || obj == HTML.Tag.UL
1946 || obj == HTML.Tag.OL)) {
1947 ret = true;
1948 }
1949
1950 return ret;
1951 }
1952
1953 static enum HorizontalMargin { LEFT, RIGHT }
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969 float getOrientationMargin(HorizontalMargin side, float cssMargin,
1970 AttributeSet a, boolean isLeftToRight) {
1971 float margin = cssMargin;
1972 float orientationMargin = cssMargin;
1973 Object cssMarginValue = null;
1974 switch (side) {
1975 case RIGHT:
1976 {
1977 orientationMargin = (isLeftToRight) ?
1978 getLength(CSS.Attribute.MARGIN_RIGHT_LTR, a) :
1979 getLength(CSS.Attribute.MARGIN_RIGHT_RTL, a);
1980 cssMarginValue = a.getAttribute(CSS.Attribute.MARGIN_RIGHT);
1981 }
1982 break;
1983 case LEFT :
1984 {
1985 orientationMargin = (isLeftToRight) ?
1986 getLength(CSS.Attribute.MARGIN_LEFT_LTR, a) :
1987 getLength(CSS.Attribute.MARGIN_LEFT_RTL, a);
1988 cssMarginValue = a.getAttribute(CSS.Attribute.MARGIN_LEFT);
1989 }
1990 break;
1991 }
1992
1993 if (cssMarginValue == null
1994 && orientationMargin != Integer.MIN_VALUE) {
1995 margin = orientationMargin;
1996 }
1997 return margin;
1998 }
1999
2000 float topMargin;
2001 float bottomMargin;
2002 float leftMargin;
2003 float rightMargin;
2004
2005
2006 short marginFlags;
2007 Border border;
2008 Insets binsets;
2009 CSS css;
2010 StyleSheet ss;
2011 Color bg;
2012 BackgroundImagePainter bgPainter;
2013 }
2014
2015
2016
2017
2018
2019
2020
2021
2022 public static class ListPainter implements Serializable {
2023
2024 ListPainter(AttributeSet attr, StyleSheet ss) {
2025 this.ss = ss;
2026
2027 String imgstr = (String)attr.getAttribute(CSS.Attribute.
2028 LIST_STYLE_IMAGE);
2029 type = null;
2030 if (imgstr != null && !imgstr.equals("none")) {
2031 String tmpstr = null;
2032 try {
2033 StringTokenizer st = new StringTokenizer(imgstr, "()");
2034 if (st.hasMoreTokens())
2035 tmpstr = st.nextToken();
2036 if (st.hasMoreTokens())
2037 tmpstr = st.nextToken();
2038 URL u = new URL(tmpstr);
2039 img = new ImageIcon(u);
2040 } catch (MalformedURLException e) {
2041 if (tmpstr != null && ss != null && ss.getBase() != null) {
2042 try {
2043 URL u = new URL(ss.getBase(), tmpstr);
2044 img = new ImageIcon(u);
2045 } catch (MalformedURLException murle) {
2046 img = null;
2047 }
2048 }
2049 else {
2050 img = null;
2051 }
2052 }
2053 }
2054
2055
2056 if (img == null) {
2057 type = (CSS.Value)attr.getAttribute(CSS.Attribute.
2058 LIST_STYLE_TYPE);
2059 }
2060 start = 1;
2061
2062 paintRect = new Rectangle();
2063 }
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073 private CSS.Value getChildType(View childView) {
2074 CSS.Value childtype = (CSS.Value)childView.getAttributes().
2075 getAttribute(CSS.Attribute.LIST_STYLE_TYPE);
2076
2077 if (childtype == null) {
2078 if (type == null) {
2079
2080 View v = childView.getParent();
2081 HTMLDocument doc = (HTMLDocument)v.getDocument();
2082 if (doc.matchNameAttribute(v.getElement().getAttributes(),
2083 HTML.Tag.OL)) {
2084 childtype = CSS.Value.DECIMAL;
2085 } else {
2086 childtype = CSS.Value.DISC;
2087 }
2088 } else {
2089 childtype = type;
2090 }
2091 }
2092 return childtype;
2093 }
2094
2095
2096
2097
2098 private void getStart(View parent) {
2099 checkedForStart = true;
2100 Element element = parent.getElement();
2101 if (element != null) {
2102 AttributeSet attr = element.getAttributes();
2103 Object startValue;
2104 if (attr != null && attr.isDefined(HTML.Attribute.START) &&
2105 (startValue = attr.getAttribute
2106 (HTML.Attribute.START)) != null &&
2107 (startValue instanceof String)) {
2108
2109 try {
2110 start = Integer.parseInt((String)startValue);
2111 }
2112 catch (NumberFormatException nfe) {}
2113 }
2114 }
2115 }
2116
2117
2118
2119
2120
2121
2122
2123
2124 private int getRenderIndex(View parentView, int childIndex) {
2125 if (!checkedForStart) {
2126 getStart(parentView);
2127 }
2128 int retIndex = childIndex;
2129 for (int counter = childIndex; counter >= 0; counter--) {
2130 AttributeSet as = parentView.getElement().getElement(counter).
2131 getAttributes();
2132 if (as.getAttribute(StyleConstants.NameAttribute) !=
2133 HTML.Tag.LI) {
2134 retIndex--;
2135 } else if (as.isDefined(HTML.Attribute.VALUE)) {
2136 Object value = as.getAttribute(HTML.Attribute.VALUE);
2137 if (value != null &&
2138 (value instanceof String)) {
2139 try {
2140 int iValue = Integer.parseInt((String)value);
2141 return retIndex - counter + iValue;
2142 }
2143 catch (NumberFormatException nfe) {}
2144 }
2145 }
2146 }
2147 return retIndex + start;
2148 }
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163 public void paint(Graphics g, float x, float y, float w, float h, View v, int item) {
2164 View cv = v.getView(item);
2165 Container host = v.getContainer();
2166 Object name = cv.getElement().getAttributes().getAttribute
2167 (StyleConstants.NameAttribute);
2168
2169
2170 if (!(name instanceof HTML.Tag) ||
2171 name != HTML.Tag.LI) {
2172 return;
2173 }
2174
2175 isLeftToRight =
2176 host.getComponentOrientation().isLeftToRight();
2177
2178
2179
2180
2181
2182
2183 float align = 0;
2184 if (cv.getViewCount() > 0) {
2185 View pView = cv.getView(0);
2186 Object cName = pView.getElement().getAttributes().
2187 getAttribute(StyleConstants.NameAttribute);
2188 if ((cName == HTML.Tag.P || cName == HTML.Tag.IMPLIED) &&
2189 pView.getViewCount() > 0) {
2190 paintRect.setBounds((int)x, (int)y, (int)w, (int)h);
2191 Shape shape = cv.getChildAllocation(0, paintRect);
2192 if (shape != null && (shape = pView.getView(0).
2193 getChildAllocation(0, shape)) != null) {
2194 Rectangle rect = (shape instanceof Rectangle) ?
2195 (Rectangle)shape : shape.getBounds();
2196
2197 align = pView.getView(0).getAlignment(View.Y_AXIS);
2198 y = rect.y;
2199 h = rect.height;
2200 }
2201 }
2202 }
2203
2204
2205 Color c = (host.isEnabled()
2206 ? (ss != null
2207 ? ss.getForeground(cv.getAttributes())
2208 : host.getForeground())
2209 : UIManager.getColor("textInactiveText"));
2210 g.setColor(c);
2211
2212 if (img != null) {
2213 drawIcon(g, (int) x, (int) y, (int) w, (int) h, align, host);
2214 return;
2215 }
2216 CSS.Value childtype = getChildType(cv);
2217 Font font = ((StyledDocument)cv.getDocument()).
2218 getFont(cv.getAttributes());
2219 if (font != null) {
2220 g.setFont(font);
2221 }
2222 if (childtype == CSS.Value.SQUARE || childtype == CSS.Value.CIRCLE
2223 || childtype == CSS.Value.DISC) {
2224 drawShape(g, childtype, (int) x, (int) y,
2225 (int) w, (int) h, align);
2226 } else if (childtype == CSS.Value.DECIMAL) {
2227 drawLetter(g, '1', (int) x, (int) y, (int) w, (int) h, align,
2228 getRenderIndex(v, item));
2229 } else if (childtype == CSS.Value.LOWER_ALPHA) {
2230 drawLetter(g, 'a', (int) x, (int) y, (int) w, (int) h, align,
2231 getRenderIndex(v, item));
2232 } else if (childtype == CSS.Value.UPPER_ALPHA) {
2233 drawLetter(g, 'A', (int) x, (int) y, (int) w, (int) h, align,
2234 getRenderIndex(v, item));
2235 } else if (childtype == CSS.Value.LOWER_ROMAN) {
2236 drawLetter(g, 'i', (int) x, (int) y, (int) w, (int) h, align,
2237 getRenderIndex(v, item));
2238 } else if (childtype == CSS.Value.UPPER_ROMAN) {
2239 drawLetter(g, 'I', (int) x, (int) y, (int) w, (int) h, align,
2240 getRenderIndex(v, item));
2241 }
2242 }
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254 void drawIcon(Graphics g, int ax, int ay, int aw, int ah,
2255 float align, Component c) {
2256
2257 int gap = isLeftToRight ? - (img.getIconWidth() + bulletgap) :
2258 (aw + bulletgap);
2259 int x = ax + gap;
2260 int y = Math.max(ay, ay + (int)(align * ah) -img.getIconHeight());
2261
2262 img.paintIcon(c, g, x, y);
2263 }
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276 void drawShape(Graphics g, CSS.Value type, int ax, int ay, int aw,
2277 int ah, float align) {
2278
2279 int gap = isLeftToRight ? - (bulletgap + 8) : (aw + bulletgap);
2280 int x = ax + gap;
2281 int y = Math.max(ay, ay + (int)(align * ah) - 8);
2282
2283 if (type == CSS.Value.SQUARE) {
2284 g.drawRect(x, y, 8, 8);
2285 } else if (type == CSS.Value.CIRCLE) {
2286 g.drawOval(x, y, 8, 8);
2287 } else {
2288 g.fillOval(x, y, 8, 8);
2289 }
2290 }
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303 void drawLetter(Graphics g, char letter, int ax, int ay, int aw,
2304 int ah, float align, int index) {
2305 String str = formatItemNum(index, letter);
2306 str = isLeftToRight ? str + "." : "." + str;
2307 FontMetrics fm = SwingUtilities2.getFontMetrics(null, g);
2308 int stringwidth = SwingUtilities2.stringWidth(null, fm, str);
2309 int gap = isLeftToRight ? - (stringwidth + bulletgap) :
2310 (aw + bulletgap);
2311 int x = ax + gap;
2312 int y = Math.max(ay + fm.getAscent(), ay + (int)(ah * align));
2313 SwingUtilities2.drawString(null, g, str, x, y);
2314 }
2315
2316
2317
2318
2319
2320
2321
2322
2323 String formatItemNum(int itemNum, char type) {
2324 String numStyle = "1";
2325
2326 boolean uppercase = false;
2327
2328 String formattedNum;
2329
2330 switch (type) {
2331 case '1':
2332 default:
2333 formattedNum = String.valueOf(itemNum);
2334 break;
2335
2336 case 'A':
2337 uppercase = true;
2338
2339 case 'a':
2340 formattedNum = formatAlphaNumerals(itemNum);
2341 break;
2342
2343 case 'I':
2344 uppercase = true;
2345
2346 case 'i':
2347 formattedNum = formatRomanNumerals(itemNum);
2348 }
2349
2350 if (uppercase) {
2351 formattedNum = formattedNum.toUpperCase();
2352 }
2353
2354 return formattedNum;
2355 }
2356
2357
2358
2359
2360
2361
2362 String formatAlphaNumerals(int itemNum) {
2363 String result;
2364
2365 if (itemNum > 26) {
2366 result = formatAlphaNumerals(itemNum / 26) +
2367 formatAlphaNumerals(itemNum % 26);
2368 } else {
2369
2370 result = String.valueOf((char)('a' + itemNum - 1));
2371 }
2372
2373 return result;
2374 }
2375
2376
2377 static final char romanChars[][] = {
2378 {'i', 'v'},
2379 {'x', 'l' },
2380 {'c', 'd' },
2381 {'m', '?' },
2382 };
2383
2384
2385
2386
2387
2388
2389 String formatRomanNumerals(int num) {
2390 return formatRomanNumerals(0, num);
2391 }
2392
2393
2394
2395
2396
2397
2398 String formatRomanNumerals(int level, int num) {
2399 if (num < 10) {
2400 return formatRomanDigit(level, num);
2401 } else {
2402 return formatRomanNumerals(level + 1, num / 10) +
2403 formatRomanDigit(level, num % 10);
2404 }
2405 }
2406
2407
2408
2409
2410
2411
2412
2413
2414 String formatRomanDigit(int level, int digit) {
2415 String result = "";
2416 if (digit == 9) {
2417 result = result + romanChars[level][0];
2418 result = result + romanChars[level + 1][0];
2419 return result;
2420 } else if (digit == 4) {
2421 result = result + romanChars[level][0];
2422 result = result + romanChars[level][1];
2423 return result;
2424 } else if (digit >= 5) {
2425 result = result + romanChars[level][1];
2426 digit -= 5;
2427 }
2428
2429 for (int i = 0; i < digit; i++) {
2430 result = result + romanChars[level][0];
2431 }
2432
2433 return result;
2434 }
2435
2436 private Rectangle paintRect;
2437 private boolean checkedForStart;
2438 private int start;
2439 private CSS.Value type;
2440 URL imageurl;
2441 private StyleSheet ss = null;
2442 Icon img = null;
2443 private int bulletgap = 5;
2444 private boolean isLeftToRight;
2445 }
2446
2447
2448
2449
2450
2451 static class BackgroundImagePainter implements Serializable {
2452 ImageIcon backgroundImage;
2453 float hPosition;
2454 float vPosition;
2455
2456
2457 short flags;
2458
2459 private int paintX;
2460 private int paintY;
2461 private int paintMaxX;
2462 private int paintMaxY;
2463
2464 BackgroundImagePainter(AttributeSet a, CSS css, StyleSheet ss) {
2465 backgroundImage = ss.getBackgroundImage(a);
2466
2467 CSS.BackgroundPosition pos = (CSS.BackgroundPosition)a.getAttribute
2468 (CSS.Attribute.BACKGROUND_POSITION);
2469 if (pos != null) {
2470 hPosition = pos.getHorizontalPosition();
2471 vPosition = pos.getVerticalPosition();
2472 if (pos.isHorizontalPositionRelativeToSize()) {
2473 flags |= 4;
2474 }
2475 else if (pos.isHorizontalPositionRelativeToSize()) {
2476 hPosition *= css.getFontSize(a, 12, ss);
2477 }
2478 if (pos.isVerticalPositionRelativeToSize()) {
2479 flags |= 8;
2480 }
2481 else if (pos.isVerticalPositionRelativeToFontSize()) {
2482 vPosition *= css.getFontSize(a, 12, ss);
2483 }
2484 }
2485
2486 CSS.Value repeats = (CSS.Value)a.getAttribute(CSS.Attribute.
2487 BACKGROUND_REPEAT);
2488 if (repeats == null || repeats == CSS.Value.BACKGROUND_REPEAT) {
2489 flags |= 3;
2490 }
2491 else if (repeats == CSS.Value.BACKGROUND_REPEAT_X) {
2492 flags |= 1;
2493 }
2494 else if (repeats == CSS.Value.BACKGROUND_REPEAT_Y) {
2495 flags |= 2;
2496 }
2497 }
2498
2499 void paint(Graphics g, float x, float y, float w, float h, View v) {
2500 Rectangle clip = g.getClipRect();
2501 if (clip != null) {
2502
2503
2504 g.clipRect((int)x, (int)y, (int)w, (int)h);
2505 }
2506 if ((flags & 3) == 0) {
2507
2508 int width = backgroundImage.getIconWidth();
2509 int height = backgroundImage.getIconWidth();
2510 if ((flags & 4) == 4) {
2511 paintX = (int)(x + w * hPosition -
2512 (float)width * hPosition);
2513 }
2514 else {
2515 paintX = (int)x + (int)hPosition;
2516 }
2517 if ((flags & 8) == 8) {
2518 paintY = (int)(y + h * vPosition -
2519 (float)height * vPosition);
2520 }
2521 else {
2522 paintY = (int)y + (int)vPosition;
2523 }
2524 if (clip == null ||
2525 !((paintX + width <= clip.x) ||
2526 (paintY + height <= clip.y) ||
2527 (paintX >= clip.x + clip.width) ||
2528 (paintY >= clip.y + clip.height))) {
2529 backgroundImage.paintIcon(null, g, paintX, paintY);
2530 }
2531 }
2532 else {
2533 int width = backgroundImage.getIconWidth();
2534 int height = backgroundImage.getIconHeight();
2535 if (width > 0 && height > 0) {
2536 paintX = (int)x;
2537 paintY = (int)y;
2538 paintMaxX = (int)(x + w);
2539 paintMaxY = (int)(y + h);
2540 if (updatePaintCoordinates(clip, width, height)) {
2541 while (paintX < paintMaxX) {
2542 int ySpot = paintY;
2543 while (ySpot < paintMaxY) {
2544 backgroundImage.paintIcon(null, g, paintX,
2545 ySpot);
2546 ySpot += height;
2547 }
2548 paintX += width;
2549 }
2550 }
2551 }
2552 }
2553 if (clip != null) {
2554
2555 g.setClip(clip.x, clip.y, clip.width, clip.height);
2556 }
2557 }
2558
2559 private boolean updatePaintCoordinates
2560 (Rectangle clip, int width, int height){
2561 if ((flags & 3) == 1) {
2562 paintMaxY = paintY + 1;
2563 }
2564 else if ((flags & 3) == 2) {
2565 paintMaxX = paintX + 1;
2566 }
2567 if (clip != null) {
2568 if ((flags & 3) == 1 && ((paintY + height <= clip.y) ||
2569 (paintY > clip.y + clip.height))) {
2570
2571 return false;
2572 }
2573 if ((flags & 3) == 2 && ((paintX + width <= clip.x) ||
2574 (paintX > clip.x + clip.width))) {
2575
2576 return false;
2577 }
2578 if ((flags & 1) == 1) {
2579 if ((clip.x + clip.width) < paintMaxX) {
2580 if ((clip.x + clip.width - paintX) % width == 0) {
2581 paintMaxX = clip.x + clip.width;
2582 }
2583 else {
2584 paintMaxX = ((clip.x + clip.width - paintX) /
2585 width + 1) * width + paintX;
2586 }
2587 }
2588 if (clip.x > paintX) {
2589 paintX = (clip.x - paintX) / width * width + paintX;
2590 }
2591 }
2592 if ((flags & 2) == 2) {
2593 if ((clip.y + clip.height) < paintMaxY) {
2594 if ((clip.y + clip.height - paintY) % height == 0) {
2595 paintMaxY = clip.y + clip.height;
2596 }
2597 else {
2598 paintMaxY = ((clip.y + clip.height - paintY) /
2599 height + 1) * height + paintY;
2600 }
2601 }
2602 if (clip.y > paintY) {
2603 paintY = (clip.y - paintY) / height * height + paintY;
2604 }
2605 }
2606 }
2607
2608 return true;
2609 }
2610 }
2611
2612
2613
2614
2615
2616
2617
2618 class ViewAttributeSet extends MuxingAttributeSet {
2619 ViewAttributeSet(View v) {
2620 host = v;
2621
2622
2623
2624 Document doc = v.getDocument();
2625 SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
2626 Vector<AttributeSet> muxList = sb.getVector();
2627 try {
2628 if (doc instanceof HTMLDocument) {
2629 StyleSheet styles = StyleSheet.this;
2630 Element elem = v.getElement();
2631 AttributeSet a = elem.getAttributes();
2632 AttributeSet htmlAttr = styles.translateHTMLToCSS(a);
2633
2634 if (htmlAttr.getAttributeCount() != 0) {
2635 muxList.addElement(htmlAttr);
2636 }
2637 if (elem.isLeaf()) {
2638 Enumeration keys = a.getAttributeNames();
2639 while (keys.hasMoreElements()) {
2640 Object key = keys.nextElement();
2641 if (key instanceof HTML.Tag) {
2642 if (key == HTML.Tag.A) {
2643 Object o = a.getAttribute(key);
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657 if (o != null && o instanceof AttributeSet) {
2658 AttributeSet attr = (AttributeSet)o;
2659 if (attr.getAttribute(HTML.Attribute.HREF) == null) {
2660 continue;
2661 }
2662 }
2663 }
2664 AttributeSet cssRule = styles.getRule((HTML.Tag) key, elem);
2665 if (cssRule != null) {
2666 muxList.addElement(cssRule);
2667 }
2668 }
2669 }
2670 } else {
2671 HTML.Tag t = (HTML.Tag) a.getAttribute
2672 (StyleConstants.NameAttribute);
2673 AttributeSet cssRule = styles.getRule(t, elem);
2674 if (cssRule != null) {
2675 muxList.addElement(cssRule);
2676 }
2677 }
2678 }
2679 AttributeSet[] attrs = new AttributeSet[muxList.size()];
2680 muxList.copyInto(attrs);
2681 setAttributes(attrs);
2682 }
2683 finally {
2684 SearchBuffer.releaseSearchBuffer(sb);
2685 }
2686 }
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700 public boolean isDefined(Object key) {
2701 if (key instanceof StyleConstants) {
2702 Object cssKey = css.styleConstantsKeyToCSSKey
2703 ((StyleConstants)key);
2704 if (cssKey != null) {
2705 key = cssKey;
2706 }
2707 }
2708 return super.isDefined(key);
2709 }
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720 public Object getAttribute(Object key) {
2721 if (key instanceof StyleConstants) {
2722 Object cssKey = css.styleConstantsKeyToCSSKey
2723 ((StyleConstants)key);
2724 if (cssKey != null) {
2725 Object value = doGetAttribute(cssKey);
2726 if (value instanceof CSS.CssValue) {
2727 return ((CSS.CssValue)value).toStyleConstants
2728 ((StyleConstants)key, host);
2729 }
2730 }
2731 }
2732 return doGetAttribute(key);
2733 }
2734
2735 Object doGetAttribute(Object key) {
2736 Object retValue = super.getAttribute(key);
2737 if (retValue != null) {
2738 return retValue;
2739 }
2740
2741
2742 if (key instanceof CSS.Attribute) {
2743 CSS.Attribute css = (CSS.Attribute) key;
2744 if (css.isInherited()) {
2745 AttributeSet parent = getResolveParent();
2746 if (parent != null)
2747 return parent.getAttribute(key);
2748 }
2749 }
2750 return null;
2751 }
2752
2753
2754
2755
2756
2757
2758
2759
2760 public AttributeSet getResolveParent() {
2761 if (host == null) {
2762 return null;
2763 }
2764 View parent = host.getParent();
2765 return (parent != null) ? parent.getAttributes() : null;
2766 }
2767
2768
2769 View host;
2770 }
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782 static class ResolvedStyle extends MuxingAttributeSet implements
2783 Serializable, Style {
2784 ResolvedStyle(String name, AttributeSet[] attrs, int extendedIndex) {
2785 super(attrs);
2786 this.name = name;
2787 this.extendedIndex = extendedIndex;
2788 }
2789
2790
2791
2792
2793
2794
2795
2796 synchronized void insertStyle(Style style, int specificity) {
2797 AttributeSet[] attrs = getAttributes();
2798 int maxCounter = attrs.length;
2799 int counter = 0;
2800 for (;counter < extendedIndex; counter++) {
2801 if (specificity > getSpecificity(((Style)attrs[counter]).
2802 getName())) {
2803 break;
2804 }
2805 }
2806 insertAttributeSetAt(style, counter);
2807 extendedIndex++;
2808 }
2809
2810
2811
2812
2813
2814 synchronized void removeStyle(Style style) {
2815 AttributeSet[] attrs = getAttributes();
2816
2817 for (int counter = attrs.length - 1; counter >= 0; counter--) {
2818 if (attrs[counter] == style) {
2819 removeAttributeSetAt(counter);
2820 if (counter < extendedIndex) {
2821 extendedIndex--;
2822 }
2823 break;
2824 }
2825 }
2826 }
2827
2828
2829
2830
2831
2832 synchronized void insertExtendedStyleAt(Style attr, int index) {
2833 insertAttributeSetAt(attr, extendedIndex + index);
2834 }
2835
2836
2837
2838
2839
2840 synchronized void addExtendedStyle(Style attr) {
2841 insertAttributeSetAt(attr, getAttributes().length);
2842 }
2843
2844
2845
2846
2847
2848 synchronized void removeExtendedStyleAt(int index) {
2849 removeAttributeSetAt(extendedIndex + index);
2850 }
2851
2852
2853
2854
2855
2856
2857 protected boolean matches(String selector) {
2858 int sLast = selector.length();
2859
2860 if (sLast == 0) {
2861 return false;
2862 }
2863 int thisLast = name.length();
2864 int sCurrent = selector.lastIndexOf(' ');
2865 int thisCurrent = name.lastIndexOf(' ');
2866 if (sCurrent >= 0) {
2867 sCurrent++;
2868 }
2869 if (thisCurrent >= 0) {
2870 thisCurrent++;
2871 }
2872 if (!matches(selector, sCurrent, sLast, thisCurrent, thisLast)) {
2873 return false;
2874 }
2875 while (sCurrent != -1) {
2876 sLast = sCurrent - 1;
2877 sCurrent = selector.lastIndexOf(' ', sLast - 1);
2878 if (sCurrent >= 0) {
2879 sCurrent++;
2880 }
2881 boolean match = false;
2882 while (!match && thisCurrent != -1) {
2883 thisLast = thisCurrent - 1;
2884 thisCurrent = name.lastIndexOf(' ', thisLast - 1);
2885 if (thisCurrent >= 0) {
2886 thisCurrent++;
2887 }
2888 match = matches(selector, sCurrent, sLast, thisCurrent,
2889 thisLast);
2890 }
2891 if (!match) {
2892 return false;
2893 }
2894 }
2895 return true;
2896 }
2897
2898
2899
2900
2901
2902
2903 boolean matches(String selector, int sCurrent, int sLast,
2904 int thisCurrent, int thisLast) {
2905 sCurrent = Math.max(sCurrent, 0);
2906 thisCurrent = Math.max(thisCurrent, 0);
2907 int thisDotIndex = boundedIndexOf(name, '.', thisCurrent,
2908 thisLast);
2909 int thisPoundIndex = boundedIndexOf(name, '#', thisCurrent,
2910 thisLast);
2911 int sDotIndex = boundedIndexOf(selector, '.', sCurrent, sLast);
2912 int sPoundIndex = boundedIndexOf(selector, '#', sCurrent, sLast);
2913 if (sDotIndex != -1) {
2914
2915
2916
2917 if (thisDotIndex == -1) {
2918 return false;
2919 }
2920 if (sCurrent == sDotIndex) {
2921 if ((thisLast - thisDotIndex) != (sLast - sDotIndex) ||
2922 !selector.regionMatches(sCurrent, name, thisDotIndex,
2923 (thisLast - thisDotIndex))) {
2924 return false;
2925 }
2926 }
2927 else {
2928
2929 if ((sLast - sCurrent) != (thisLast - thisCurrent) ||
2930 !selector.regionMatches(sCurrent, name, thisCurrent,
2931 (thisLast - thisCurrent))) {
2932 return false;
2933 }
2934 }
2935 return true;
2936 }
2937 if (sPoundIndex != -1) {
2938
2939
2940
2941 if (thisPoundIndex == -1) {
2942 return false;
2943 }
2944 if (sCurrent == sPoundIndex) {
2945 if ((thisLast - thisPoundIndex) !=(sLast - sPoundIndex) ||
2946 !selector.regionMatches(sCurrent, name, thisPoundIndex,
2947 (thisLast - thisPoundIndex))) {
2948 return false;
2949 }
2950 }
2951 else {
2952
2953 if ((sLast - sCurrent) != (thisLast - thisCurrent) ||
2954 !selector.regionMatches(sCurrent, name, thisCurrent,
2955 (thisLast - thisCurrent))) {
2956 return false;
2957 }
2958 }
2959 return true;
2960 }
2961 if (thisDotIndex != -1) {
2962
2963 return (((thisDotIndex - thisCurrent) == (sLast - sCurrent)) &&
2964 selector.regionMatches(sCurrent, name, thisCurrent,
2965 thisDotIndex - thisCurrent));
2966 }
2967 if (thisPoundIndex != -1) {
2968
2969 return (((thisPoundIndex - thisCurrent) ==(sLast - sCurrent))&&
2970 selector.regionMatches(sCurrent, name, thisCurrent,
2971 thisPoundIndex - thisCurrent));
2972 }
2973
2974 return (((thisLast - thisCurrent) == (sLast - sCurrent)) &&
2975 selector.regionMatches(sCurrent, name, thisCurrent,
2976 thisLast - thisCurrent));
2977 }
2978
2979
2980
2981
2982
2983
2984 int boundedIndexOf(String string, char search, int start,
2985 int end) {
2986 int retValue = string.indexOf(search, start);
2987 if (retValue >= end) {
2988 return -1;
2989 }
2990 return retValue;
2991 }
2992
2993 public void addAttribute(Object name, Object value) {}
2994 public void addAttributes(AttributeSet attributes) {}
2995 public void removeAttribute(Object name) {}
2996 public void removeAttributes(Enumeration<?> names) {}
2997 public void removeAttributes(AttributeSet attributes) {}
2998 public void setResolveParent(AttributeSet parent) {}
2999 public String getName() {return name;}
3000 public void addChangeListener(ChangeListener l) {}
3001 public void removeChangeListener(ChangeListener l) {}
3002 public ChangeListener[] getChangeListeners() {
3003 return new ChangeListener[0];
3004 }
3005
3006
3007
3008
3009 String name;
3010
3011 private int extendedIndex;
3012 }
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023 static class SelectorMapping implements Serializable {
3024 public SelectorMapping(int specificity) {
3025 this.specificity = specificity;
3026 }
3027
3028
3029
3030
3031 public int getSpecificity() {
3032 return specificity;
3033 }
3034
3035
3036
3037
3038 public void setStyle(Style style) {
3039 this.style = style;
3040 }
3041
3042
3043
3044
3045 public Style getStyle() {
3046 return style;
3047 }
3048
3049
3050
3051
3052
3053
3054
3055 public SelectorMapping getChildSelectorMapping(String selector,
3056 boolean create) {
3057 SelectorMapping retValue = null;
3058
3059 if (children != null) {
3060 retValue = children.get(selector);
3061 }
3062 else if (create) {
3063 children = new HashMap<String, SelectorMapping>(7);
3064 }
3065 if (retValue == null && create) {
3066 int specificity = getChildSpecificity(selector);
3067
3068 retValue = createChildSelectorMapping(specificity);
3069 children.put(selector, retValue);
3070 }
3071 return retValue;
3072 }
3073
3074
3075
3076
3077
3078 protected SelectorMapping createChildSelectorMapping(int specificity) {
3079 return new SelectorMapping(specificity);
3080 }
3081
3082
3083
3084
3085
3086 protected int getChildSpecificity(String selector) {
3087
3088
3089 char firstChar = selector.charAt(0);
3090 int specificity = getSpecificity();
3091
3092 if (firstChar == '.') {
3093 specificity += 100;
3094 }
3095 else if (firstChar == '#') {
3096 specificity += 10000;
3097 }
3098 else {
3099 specificity += 1;
3100 if (selector.indexOf('.') != -1) {
3101 specificity += 100;
3102 }
3103 if (selector.indexOf('#') != -1) {
3104 specificity += 10000;
3105 }
3106 }
3107 return specificity;
3108 }
3109
3110
3111
3112
3113 private int specificity;
3114
3115
3116
3117 private Style style;
3118
3119
3120
3121
3122 private HashMap<String, SelectorMapping> children;
3123 }
3124
3125
3126
3127
3128 final static int DEFAULT_FONT_SIZE = 3;
3129
3130 private CSS css;
3131
3132
3133
3134
3135 private SelectorMapping selectorMapping;
3136
3137
3138
3139 private Hashtable<String, ResolvedStyle> resolvedStyles;
3140
3141
3142
3143 private Vector<StyleSheet> linkedStyleSheets;
3144
3145
3146 private URL base;
3147
3148
3149
3150
3151
3152
3153
3154
3155 class CssParser implements CSSParser.CSSParserCallback {
3156
3157
3158
3159
3160 public AttributeSet parseDeclaration(String string) {
3161 try {
3162 return parseDeclaration(new StringReader(string));
3163 } catch (IOException ioe) {}
3164 return null;
3165 }
3166
3167
3168
3169
3170 public AttributeSet parseDeclaration(Reader r) throws IOException {
3171 parse(base, r, true, false);
3172 return declaration.copyAttributes();
3173 }
3174
3175
3176
3177
3178 public void parse(URL base, Reader r, boolean parseDeclaration,
3179 boolean isLink) throws IOException {
3180 this.base = base;
3181 this.isLink = isLink;
3182 this.parsingDeclaration = parseDeclaration;
3183 declaration.removeAttributes(declaration);
3184 selectorTokens.removeAllElements();
3185 selectors.removeAllElements();
3186 propertyName = null;
3187 parser.parse(r, this, parseDeclaration);
3188 }
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200 public void handleImport(String importString) {
3201 URL url = CSS.getURL(base, importString);
3202 if (url != null) {
3203 importStyleSheet(url);
3204 }
3205 }
3206
3207
3208
3209
3210 public void handleSelector(String selector) {
3211
3212 if (!(selector.startsWith(".")
3213 || selector.startsWith("#"))) {
3214 selector = selector.toLowerCase();
3215 }
3216 int length = selector.length();
3217
3218 if (selector.endsWith(",")) {
3219 if (length > 1) {
3220 selector = selector.substring(0, length - 1);
3221 selectorTokens.addElement(selector);
3222 }
3223 addSelector();
3224 }
3225 else if (length > 0) {
3226 selectorTokens.addElement(selector);
3227 }
3228 }
3229
3230
3231
3232
3233 public void startRule() {
3234 if (selectorTokens.size() > 0) {
3235 addSelector();
3236 }
3237 propertyName = null;
3238 }
3239
3240
3241
3242
3243 public void handleProperty(String property) {
3244 propertyName = property;
3245 }
3246
3247
3248
3249
3250 public void handleValue(String value) {
3251 if (propertyName != null && value != null && value.length() > 0) {
3252 CSS.Attribute cssKey = CSS.getAttribute(propertyName);
3253 if (cssKey != null) {
3254
3255
3256
3257
3258
3259 if (cssKey == CSS.Attribute.LIST_STYLE_IMAGE) {
3260 if (value != null && !value.equals("none")) {
3261 URL url = CSS.getURL(base, value);
3262
3263 if (url != null) {
3264 value = url.toString();
3265 }
3266 }
3267 }
3268 addCSSAttribute(declaration, cssKey, value);
3269 }
3270 propertyName = null;
3271 }
3272 }
3273
3274
3275
3276
3277 public void endRule() {
3278 int n = selectors.size();
3279 for (int i = 0; i < n; i++) {
3280 String[] selector = selectors.elementAt(i);
3281 if (selector.length > 0) {
3282 StyleSheet.this.addRule(selector, declaration, isLink);
3283 }
3284 }
3285 declaration.removeAttributes(declaration);
3286 selectors.removeAllElements();
3287 }
3288
3289 private void addSelector() {
3290 String[] selector = new String[selectorTokens.size()];
3291 selectorTokens.copyInto(selector);
3292 selectors.addElement(selector);
3293 selectorTokens.removeAllElements();
3294 }
3295
3296
3297 Vector<String[]> selectors = new Vector<String[]>();
3298 Vector<String> selectorTokens = new Vector<String>();
3299
3300 String propertyName;
3301 MutableAttributeSet declaration = new SimpleAttributeSet();
3302
3303
3304 boolean parsingDeclaration;
3305
3306 boolean isLink;
3307
3308 URL base;
3309 CSSParser parser = new CSSParser();
3310 }
3311
3312 void rebaseSizeMap(int base) {
3313 final int minimalFontSize = 4;
3314 sizeMap = new int[sizeMapDefault.length];
3315 for (int i = 0; i < sizeMapDefault.length; i++) {
3316 sizeMap[i] = Math.max(base * sizeMapDefault[i] /
3317 sizeMapDefault[CSS.baseFontSizeIndex],
3318 minimalFontSize);
3319 }
3320
3321 }
3322
3323 int[] getSizeMap() {
3324 return sizeMap;
3325 }
3326 boolean isW3CLengthUnits() {
3327 return w3cLengthUnits;
3328 }
3329
3330
3331
3332
3333
3334 static final int sizeMapDefault[] = { 8, 10, 12, 14, 18, 24, 36 };
3335
3336 private int sizeMap[] = sizeMapDefault;
3337 private boolean w3cLengthUnits = false;
3338 }